package com.hystrix.controller;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.hystrix.command.CollapserCommand;
import com.hystrix.command.FallBackCommand;
import com.hystrix.command.FallBackNestCommand;
import com.hystrix.command.ObservableReactiveCommand;
import com.hystrix.command.RequestCacheCommand;
import com.hystrix.command.ServiceAInfoCommand;
import com.hystrix.command.ServiceAMaxThreadCommand;
import com.hystrix.command.ServiceBInfoCommand;
import com.hystrix.http.HttpPost;
import com.hystrix.model.InfoA;
import com.hystrix.model.InfoB;
import com.hystrix.util.Constant;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;

import io.swagger.annotations.ApiOperation;
import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;

@RestController
@RequestMapping(value = "/service")
public class ServiceController {

	/**
	 * 初用Hystrix请求外部接口
	 * 
	 * @return
	 */
	@ApiOperation(value = "一般的接口请求", notes = "")
	@RequestMapping(value = "/general", method = { RequestMethod.GET, RequestMethod.POST })
	public String general() {
		String a = HttpPost.httpPost(Constant.serviceA, "", "utf-8");
		String b = HttpPost.httpPost(Constant.serviceB, "", "utf-8");
		return "我是没有使用Hystrix的综合服务：" + a + " === " + b;
	}

	/**
	 * 继承了了Hystrix的HystrixCommand接口
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的一般接口请求", notes = "")
	@RequestMapping(value = "/hystrix", method = { RequestMethod.GET, RequestMethod.POST })
	public String hystrix() {
		ServiceAInfoCommand acommand = new ServiceAInfoCommand();
		InfoA a = acommand.execute();
		ServiceBInfoCommand bcommand = new ServiceBInfoCommand();
		InfoB b = bcommand.execute();
		return "我是使用Hystrix的综合服务：" + a + " === " + b;
	}

	/**
	 * 异步调用HystrixCommand
	 * 
	 * @return
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	@ApiOperation(value = "使用Hystrix的异步调用接口请求", notes = "")
	@RequestMapping(value = "/hystrix/asyn", method = { RequestMethod.GET, RequestMethod.POST })
	public String hystrixAsyn() throws InterruptedException, ExecutionException {
		ServiceAInfoCommand acommand = new ServiceAInfoCommand();
		Future<InfoA> a = acommand.queue();
		InfoA b = a.get();
		return "我是使用Hystrix的异步调用：" + b;
	}

	/**
	 * 被动执行
	 * 
	 * Hot Observable
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的被动执行接口请求", notes = "返回一个立即执行了Command的Observable")
	@RequestMapping(value = "/hystrix/hot/reactive", method = { RequestMethod.GET, RequestMethod.POST })
	public String hystrixHotReactive() {
		ObservableReactiveCommand command = new ObservableReactiveCommand("hot");
		Observable<String> b = command.observe();
		try {
			Thread.sleep(10000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Subscription sub = b.subscribe(new Action1<String>() {
			@Override
			public void call(String t) {
				System.out.println(t);
			}
		});
		return sub.isUnsubscribed() + "";
	}

	/**
	 * 被动执行
	 * 
	 * Cold Observable
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的被动执行接口请求", notes = "返回一个没有执行的Observable，只有当执行subscribe时才调用接口")
	@RequestMapping(value = "/hystrix/cold/reactive", method = { RequestMethod.GET, RequestMethod.POST })
	public String hystrixColdeReactive() {
		ObservableReactiveCommand command = new ObservableReactiveCommand("cold");
		Observable<String> b = command.toObservable();
		try {
			Thread.sleep(10000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Subscription sub = b.subscribe(new Action1<String>() {
			@Override
			public void call(String t) {
				System.out.println(t);
			}
		});
		return sub.isUnsubscribed() + "";
	}

	/**
	 * 降级逻辑接口
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的降级逻辑接口接口请求", notes = "除了HystrixBadRequestException异常之外，所有从run()方法抛出的异常都算作失败，并触发降级getFallback()和断路器逻辑。")
	@RequestMapping(value = "/hystrix/fallback", method = { RequestMethod.GET, RequestMethod.POST })
	public String fallback() {
		FallBackCommand command = new FallBackCommand("test-Fallback");
		String result = command.execute();
		return result;
	}

	/**
	 * 降级逻辑嵌套
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的异步调用接口请求", notes = "当发生异常时，在fallback中调用另一个command执行降级嵌套")
	@RequestMapping(value = "/hystrix/fallback/nest", method = { RequestMethod.GET, RequestMethod.POST })
	public String fallbackNest() {
		FallBackNestCommand command = new FallBackNestCommand();
		String result = command.execute();
		return result;
	}

	/**
	 * Request Cache
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的异步调用接口请求", notes = "当多次对同一接口进行请求时，将返回数据进行缓存，后续请求将不再请求接口直接请求缓存 \n "
			+ "只能对每次请求中相同的请求进行缓存 \n " + "每次请求需要一个请求上下文HystrixRequestContext，不同上下文不是一份缓存")
	@RequestMapping(value = "/hystrix/request/cache", method = { RequestMethod.GET, RequestMethod.POST })
	public String requestCache(String cacheIds) {
		HystrixRequestContext context = HystrixRequestContext.initializeContext();
		StringBuffer result = new StringBuffer();
		try {
			String[] cacheId = cacheIds.split(",");
			for (int i = 0; i < cacheId.length; i++) {
				RequestCacheCommand command = new RequestCacheCommand(cacheId[i]);
				String res = command.execute();
				boolean resb = command.isResponseFromCache();
				System.out.println("请求cacheId：" + cacheId[i] + "请求结果：" + res + " ==== 来源cache：" + resb);
				result.append("请求cacheId：" + cacheId[i] + "请求结果：" + res + " ==== 来源cache：" + resb).append("</br>");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			context.shutdown();
		}
		return result.toString();
	}

	/**
	 * 合并请求
	 * 
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的合并接口请求", notes = "")
	@RequestMapping(value = "/hystrix/collapser", method = { RequestMethod.GET, RequestMethod.POST })
	public String collapserCommand() {
		HystrixRequestContext context = HystrixRequestContext.initializeContext();
		StringBuffer result = new StringBuffer();
		try {
			Future<String> f1 = new CollapserCommand(1).queue();
			Future<String> f2 = new CollapserCommand(2).queue();
			Future<String> f3 = new CollapserCommand(3).queue();
			Future<String> f4 = new CollapserCommand(4).queue();
			result.append(f1.get()).append("</br>");
			result.append(f2.get()).append("</br>");
			result.append(f3.get()).append("</br>");
			result.append(f4.get()).append("</br>");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			context.shutdown();
		}
		return result.toString();
	}

	/**
	 * 线程池大小
	 * 
	 * @param num
	 * @return
	 */
	@ApiOperation(value = "使用Hystrix的线程池大小控制请求", notes = "当设置了线程池大小时，同一时间并发超过线程池大小的请求过来时，只能通过制定大小的个数请求，其余请求将失败")
	@RequestMapping(value = "/hystrix/maxThread", method = { RequestMethod.GET, RequestMethod.POST })
	public String threadIsolation(int num) {
		ServiceAMaxThreadCommand acommand = new ServiceAMaxThreadCommand(num);
		InfoA a = acommand.execute();
		return JSONObject.toJSONString(a);
	}

	public String pullRequest() {

		return "";
	}

}
